
// class Navigation manage the player navigation
public class Navigation {

	 double	alpha = 90, alpha_step = 5;
     double	beta = 0, beta_step = 5;
     double	step=20;
	private Location location;
	private LevelBuilder mapBuilder;
	private int humanHight = 150;
	private Portal portal ;
	private Switcher switcher;
	
	private double downSpeed=0;
	

	
	public Navigation(Portal p,Switcher switcher) {
		location= new Location();
		location.upVector=new Point3D(0,1, 0);
		location.eyePosition=new Point3D(100, humanHight, 100);
		location.lookAtPoint = new Point3D();
		updatelookAt();

		this.portal=p;
		this.switcher=switcher;
		
		
	}
	private void updatelookAt(){
		location.lookAtPoint.x=location.eyePosition.x+(Utils.COS(beta)*Utils.COS(alpha));
		location.lookAtPoint.y=location.eyePosition.y+Utils.SIN(beta);
		location.lookAtPoint.z=location.eyePosition.z+(Utils.COS(beta)*Utils.SIN(alpha));
	}
	public Location getLocation() {
		return location;
	}

	public void moveForward() {
		
		if (!inpact(location.eyePosition.x+step*2*Utils.COS(alpha),location.eyePosition.z +step*2*Utils.SIN(alpha))){
		    location.eyePosition.x += step*Utils.COS(alpha);
		    //location.eyePosition.y += step*SIN(beta);
		    location.eyePosition.z += step*Utils.SIN(alpha);
		    
		    updatelookAt();
		    Point3D [] p =portal.checkPortalEnterance(location.getEyePosition());
		    if (p!=null)
		    	updateLocationByPortal(p[0],p[1],p[2]);
		    
		}
		    
		
	}
	
	public void updateLocationByPortal(Point3D point, Point3D gateNormal,Point3D orgNor) {
		location.eyePosition.x=point.x;
		location.eyePosition.y=point.y;
		location.eyePosition.z=point.z;
		
		
		
	
		if (gateNormal.z==-1 && orgNor.x==-1)
			alpha=270+alpha;
		if (gateNormal.z==-1 && orgNor.z==-1)
			alpha=180+alpha;
		if (gateNormal.z==-1 && orgNor.x==1)
			alpha=180+alpha;

	//	if (gateNormal.z==-1 && orgNor.z==1)
			//alpha=180+alpha;

			
		if (gateNormal.z==1 && orgNor.z==1)
			alpha=180+alpha;
		if (gateNormal.z==1 && orgNor.x==-1)
			alpha=90-alpha;
		//if (gateNormal.z==1 && orgNor.z==-1){
			//alpha=+alpha;
		
	//	}
		if (gateNormal.z==1 && orgNor.x==1)
			alpha=270-alpha;

		if (gateNormal.x==1 && orgNor.z==1)
			alpha=90+alpha;

		//if (gateNormal.x==1 && orgNor.x==-1){
			//alpha=90+alpha;
			//System.out.println("9");
		//}
		if (gateNormal.x==1 && orgNor.z==-1)
			alpha=270+alpha;

		
		if (gateNormal.x==1 && orgNor.x==1)
			alpha=180+alpha;
		if (gateNormal.x==-1 && orgNor.z==1)
			alpha=90-alpha;

		if (gateNormal.x==-1 && orgNor.x==-1)
			alpha=180+alpha;

		if (gateNormal.x==-1 && orgNor.z==-1)
			alpha=90+alpha;

	//	if (gateNormal.x==-1 && orgNor.x==1){
			//alpha=90+alpha;
		//	System.out.println("15");
	//	}
		
		//beta=0;
		updatelookAt();
		
	}

	private boolean inpact(double d, double e) {
		Point3D points[] =mapBuilder.getRoomWalls(location.getRoomNumber());
		double al = 0;
		Point3D lo = new Point3D(d,location.getEyePosition().y,e);
		
		Point3D v1 = lo.minus(points[0]);
		Point3D v2 = lo.minus(points[1]);
		al += v1.calculateAngle(v2);
		Point3D v3 = lo.minus(points[2]);
		al += v2.calculateAngle(v3);
		Point3D v4 = lo.minus(points[3]);
		al += v3.calculateAngle(v4);
		
		al += v4.calculateAngle(v1);
		
		//calc opening angle
		Point3D v6= lo.minus(points[4]);
		Point3D v5= lo.minus(points[5]);
		double beta1 =v5.calculateAngle(v6);

		
		
		if (al<359 ){

			if (beta1>=90 ){
				location.setRoomNumber(1);
				
				return false;
			}
			return true;
		}else
			return false;
		
		
	}
	public void moveBackward() {
		if (!inpact(location.eyePosition.x-step*3*Utils.COS(alpha),location.eyePosition.z -step*3*Utils.SIN(alpha))){
			location.eyePosition.x -= step*Utils.COS(alpha);
			//location.eyePosition.y -= step*SIN(beta);
			location.eyePosition.z -= step*Utils.SIN(alpha);
			updatelookAt();
		    Point3D [] p =portal.checkPortalEnterance(location.getEyePosition());
		    if (p!=null)
		    	updateLocationByPortal(p[0],p[1],p[2]);
		    
		}
		
		
	}


	public void moveLeft() {
		if (!inpact(location.eyePosition.x-3*step*Utils.COS(90+alpha),location.eyePosition.z -3*step*Utils.SIN(90+alpha))){
			location.eyePosition.x -= step*Utils.COS(90+alpha);
			location.eyePosition.z -= step*Utils.SIN(90+alpha);
			updatelookAt();
		    Point3D [] p =portal.checkPortalEnterance(location.getEyePosition());
		    if (p!=null)
		    	updateLocationByPortal(p[0],p[1],p[2]);
		}
		
	}
	public void moveRight() {
		if (!inpact(location.eyePosition.x+3*step*Utils.COS(90+alpha),location.eyePosition.z +3*step*Utils.SIN(90+alpha))){
			location.eyePosition.x += step*Utils.COS(90+alpha);
			location.eyePosition.z += step*Utils.SIN(90+alpha);
			updatelookAt();
		    Point3D [] p =portal.checkPortalEnterance(location.getEyePosition());
		    if (p!=null)
		    	updateLocationByPortal(p[0],p[1],p[2]);
		}
		
	}
	public void moveHeadUp() {
		if (beta<90){
			beta+=beta_step;
			updatelookAt();
		}
	}
	public void moveHeadDown() {
		if (beta>-90){
			beta-=beta_step;
			updatelookAt();
		}
		
	}
	public void moveHeadLeft() {
		alpha -= alpha_step;
		updatelookAt();
		
	}
	public void moveHeadRight() {
		alpha += alpha_step;
		updatelookAt();
		
	}
	public void setMapBuilder(LevelBuilder mapBuilder) {
		this.mapBuilder=mapBuilder;
		
	}
	public void updatePersonPosition() {
		if (!onFloor(location.eyePosition.x,location.eyePosition.z ,location.eyePosition.y)){

			if (downSpeed<=1)
				downSpeed +=0.001;
			location.eyePosition.y -= downSpeed;
			location.lookAtPoint.y-= downSpeed;
		}
		Point3D [] p =portal.checkPortalEnterance(location.getEyePosition());
	    if (p!=null)
	    	updateLocationByPortal(p[0],p[1],p[2]);
	    
	    //switch check
	    if (switcher!=null)
	    	switcher.checkActive(location.getEyePosition(),1);
	  
		
	}
	private boolean onFloor(double x, double z,double y) {
		
		if (y>150)
			return false;
		
		Point3D points[] =mapBuilder.getFloorPoints();
		double al = 0;
		Point3D lo = new Point3D(x,0,z-110);
		
		if (points==null)
			return true;
		
		Point3D v1 = lo.minus(points[0]);
		Point3D v2 = lo.minus(points[1]);
		al += v1.calculateAngle(v2);
		Point3D v3 = lo.minus(points[2]);
		al += v2.calculateAngle(v3);
		Point3D v4 = lo.minus(points[3]);
		al += v3.calculateAngle(v4);
		
		al += v4.calculateAngle(v1);

		if (al<359 ){
			
			return true;
		}else{
			//System.out.print(al+ " ");
			return false;
		}
		

	}



}


